#include "CentralCache.h"
#include "PageCache.h"

CentralCache CentralCache::_sInst;
// 获取空的span
Span *CentralCache::GetOneSpan(SpanList &List, size_t size)
{
    // 首先找有无多余的span
    // 有未分配的span对象
    Span *it = List.Begin();
    while (it != List.End())
    {
        if (it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }
    List.UnLock();
    // 没有向PageCache找
    // 根据size看pageCache会切几页
    PageCache::Lock();
    Span *span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    span->_isUse = true;
    span->_size = size;
    PageCache::UnLock();

    // 获取到span,对span进行切分
    // void* 不能做加减法！！！！！！！！！！！！！！！！！！！！！！！！！！注意！！！！！
    char *start = (char *)(span->_PageId << ShiftPageSize);
    size_t bytes = span->_n << ShiftPageSize;
    // char *end = (char *)((span->_PageId + span->_n) << ShiftPageSize);
    char *end = start + bytes;


    // 插入自由链表_freeList中
    //先切一块做头
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;
    while (start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }
    //将最后一块小内存置空
    NextObj(tail) = nullptr;
    // 将span挂上CentralCache上
    List.Lock();
    List.PushFront(span);

    return span;
}
// 从中心缓存获取内存给threadCache(获取一个切分好的span内存给threadCache)
size_t CentralCache::FetchRangeObj(void *&start, void *&end, size_t bachNum, size_t size)
{
    assert(_spanLists);
    size_t index = SizeClass::Index(size);

    _spanLists[index].Lock();
    // 桶锁锁住了，内部不用上锁了
    Span *span = GetOneSpan(_spanLists[index], size);

    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    // end = NextObj(start);
    end = start;

    // _spanLists[index]._spanMap[(PageId_t)start >> ShiftPageSize] = span;

    size_t numObj = 1;
    while (numObj < bachNum && NextObj(end) != nullptr)
    {
        // _spanLists[index]._spanMap[(PageId_t)end >> ShiftPageSize] = span;
        end = NextObj(end);
        ++numObj;
    }

    span->_freeList = NextObj(end);

    NextObj(end) = nullptr;

    span->_useCount += numObj;

    _spanLists[index].UnLock();


    return numObj;
}
void CentralCache::ObjGiveBack(size_t size, void *start)
{
    size_t index = SizeClass::Index(size);
    _spanLists[index].Lock();
    assert(start);
    while (start)
    {
        void *next = NextObj(start);
        Span *span = PageCache::GetInstance()->MapObjToSpan(start);

        // assert(span);
        // freeList -> start node
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        --(span->_useCount);

        // 所有小块内存都回去了
        if (span->_useCount == 0)
        {
            _spanLists[index].Erase(span);
            span->_next = nullptr;
            span->_prev = nullptr;
            span->_freeList = nullptr;
            // 向PageCache回收
            _spanLists[index].UnLock();

            PageCache::Lock();
            PageCache::GetInstance()->SpnaGiveBackPage(span);
            PageCache::UnLock();

            _spanLists[index].Lock();
        }
        start = next;
    }
    _spanLists[index].UnLock();
}
